#pragma once

#include "value.h"
#include "map.h"
#include "list.h"
#include "io.h"
#include "stdlib.h"

#define END_OF_BIND				{ NULL, NONE, NULL }
#define END_OF_BIND_STATIC		{ 0, NONE, NULL }
#define OFFSET_OF(type, var)	(int) (&((type *) NULL)->var)

#define XML_FOR_EACH(parent, index) \
	for (index = 0; index < (parent)->getChildCount (parent); index++)

#define XML_EACH_CHILD(parent, index) \
	(parent)->getChildByIndex ((parent), index);

#define IS_XML_VALUE_TRUE(value) \
		((value != NULL) && (STRING_EQUAL_IGNORECASE ((value), "true") || STRING_EQUAL ((value), "1")))

struct _xml_bind_static;
typedef struct _xml_bind_static XMLBIND_STATIC, *PXMLBIND_STATIC;
struct _xml_bind_static
{
	int        offset;
	VALUE_TYPE type;
	char       *name;
};

struct _xml_bind;
typedef struct _xml_bind XMLBIND, *PXMLBIND;
struct _xml_bind
{
	void       *address;
	VALUE_TYPE type;
	char       *name;
};

struct _xml_node;
typedef struct _xml_node XMLNODE, *PXMLNODE;
struct _xml_node
{
	bool (*destroy) (PXMLNODE);

	char* (*getName) (PXMLNODE);
	char* (*getTextContent) (PXMLNODE);
	char* (*getAttribute) (PXMLNODE, char *);
	PXMLNODE (*getChildById) (PXMLNODE, char *);
	PXMLNODE (*getChildByAttribute) (PXMLNODE, char *, char *);
	PXMLNODE (*getChildByIndex) (PXMLNODE, int);
	PXMLNODE (*getChildByName) (PXMLNODE, char *, int);
	PXMLNODE (*getDescentByName) (PXMLNODE, int, ...);
	char* (*getChildTextContentByName) (PXMLNODE, char *, int);
	size_t (*getChildrenByAttribute) (PXMLNODE, PXMLNODE, char *, char *);
	int (*getChildIndex) (PXMLNODE, PXMLNODE);
	PXMLNODE (*getParent) (PXMLNODE);
	size_t (*getAttributeCount) (PXMLNODE);
	size_t (*getChildCount) (PXMLNODE);
	
	bool (*hasChild) (PXMLNODE, PXMLNODE);

	bool (*setName) (PXMLNODE, char *);
	bool (*setTextContent) (PXMLNODE, char *);
	bool (*appendAttribute) (PXMLNODE, char *, char *);
	PXMLNODE (*appendChild) (PXMLNODE, PXMLNODE);

	bool (*removeAttribute) (PXMLNODE, char *);
	PXMLNODE (*removeChild) (PXMLNODE, PXMLNODE);
	PXMLNODE (*removeChildByIndex) (PXMLNODE, int);

	int (*readXML) (PXMLNODE, PREADER);
	bool (*writeXML) (PXMLNODE, PWRITER);
	bool (*writeXMLNoWS) (PXMLNODE, PWRITER);

	bool (*bind)       (PXMLNODE, PXMLBIND);
	bool (*bindStatic) (PXMLNODE, PXMLBIND_STATIC, void *);

	PXMLNODE parent;
	PMAP attributeMap;
	PLIST childList;
	char *textContent;
	char *name;
};

PXMLNODE xml_node_create (PXMLNODE);
PXMLNODE xml_node_copy (PXMLNODE);

